package atomic

import (
	"sync"
	"sync/atomic"
	"unsafe"
)
//判断是不是64位
func is64BitSystem() bool {
	return unsafe.Sizeof(int(0)) == 8
}

type atomicInt64 struct {
	is64Bit bool
	value   int64
	mutex   sync.Mutex
}

func NewAtomicInt64() *atomicInt64 {
	return &atomicInt64{
		is64Bit: is64BitSystem(),
	}
}

func (a *atomicInt64) Load() int64 {
	if a.is64Bit {
		return atomic.LoadInt64((*int64)(unsafe.Pointer(&a.value)))
	} else {
		a.mutex.Lock()
		defer a.mutex.Unlock()
		return a.value
	}
}

func (a *atomicInt64) Store(val int64) {
	if a.is64Bit {
		atomic.StoreInt64((*int64)(unsafe.Pointer(&a.value)), val)
	} else {
		a.mutex.Lock()
		defer a.mutex.Unlock()
		a.value = val
	}
}

func (a *atomicInt64) Add(delta int64) int64 {
	if a.is64Bit {
		return atomic.AddInt64((*int64)(unsafe.Pointer(&a.value)), delta)
	} else {
		a.mutex.Lock()
		defer a.mutex.Unlock()
		oldVal := a.value
		a.value += delta
		return oldVal
	}
}

func (a *atomicInt64) Sub(delta int64) int64 {
	return a.Add(-delta)
}

func (a *atomicInt64) CompareAndSwap(old, new int64) bool {
	if a.is64Bit {
		return atomic.CompareAndSwapInt64((*int64)(unsafe.Pointer(&a.value)), old, new)
	} else {
		a.mutex.Lock()
		defer a.mutex.Unlock()
		if a.value == old {
			a.value = new
			return true
		}
		return false
	}
}




type atomicUint64 struct {
	is64Bit bool
	value   uint64
	mutex   sync.Mutex
}

func NewAtomicUint64() *atomicUint64 {
	return &atomicUint64{
		is64Bit: is64BitSystem(),
	}
}

func (a *atomicUint64) Load() uint64 {
	if a.is64Bit {
		return atomic.LoadUint64((*uint64)(unsafe.Pointer(&a.value)))
	} else {
		a.mutex.Lock()
		defer a.mutex.Unlock()
		return a.value
	}
}

func (a *atomicUint64) Store(val uint64) {
	if a.is64Bit {
		atomic.StoreUint64((*uint64)(unsafe.Pointer(&a.value)), val)
	} else {
		a.mutex.Lock()
		defer a.mutex.Unlock()
		a.value = val
	}
}

func (a *atomicUint64) Add(delta uint64) uint64 {
	if a.is64Bit {
		return atomic.AddUint64((*uint64)(unsafe.Pointer(&a.value)), delta)
	} else {
		a.mutex.Lock()
		defer a.mutex.Unlock()
		oldVal := a.value
		a.value += delta
		return oldVal
	}
}

func (a *atomicUint64) Sub(delta uint64) uint64 {
	return a.Add(^delta + 1)
}

func (a *atomicUint64) CompareAndSwap(old, new uint64) bool {
	if a.is64Bit {
		return atomic.CompareAndSwapUint64((*uint64)(unsafe.Pointer(&a.value)), old, new)
	} else {
		a.mutex.Lock()
		defer a.mutex.Unlock()
		if a.value == old {
			a.value = new
			return true
		}
		return false
	}
}

func (a *atomicUint64) Swap(newVal uint64) uint64 {
	if a.is64Bit {
		return atomic.SwapUint64((*uint64)(unsafe.Pointer(&a.value)), newVal)
	} else {
		a.mutex.Lock()
		defer a.mutex.Unlock()
		oldVal := a.value
		a.value = newVal
		return oldVal
	}
}

